本番環境のLambdaをステップ実行!! Lambdaのカスタムランタイム環境(PHP用)にExtensionを組み込んでみた #reinvent
本番環境のLambdaをステップ実行してデバッグすることは可能ですが、実行時間に応じて課金が発生する点についてご留意下さい。
はじめに
サーバーレス開発部@大阪の岩田です。 re:Invent2018で発表されたLambdaのCustom Runtime機能でPHPを動かしてみたので、手順等をご紹介します。
Custom Runtime機能については既に色々とブログが公開されているので、下記のブログもご参照下さい。
【アップデート】 もう言語で悩まない!AWS LambdaでCustom Runtimeが利用できるようになりました! #reinvent
AWS Lambda の新機能でサーバーレス・シェルスクリプト! カスタムランタイムのチュートリアルを動かしてみた #reinvent
やること
- LambdaのCustom Runtime機能を使いPHPのコードを動かす
- PHPのCustom Runtime環境を拡張し、Extension(Xdebug)を導入する
- 導入したExtension(Xdebug)を使ってLambdaのコードをリモートデバッグする
やってみる
まずは簡単なPHPのコードを動かしてみます。
PHPのCustom RuntimeはStackery社から提供されています。 Stackery社のGitHubリポジトリのREADMEを参考に進めていきます。
コード
ディレクトリ構成は下記のような構造になります。
└── lambda ├── src │ └── php │ └── index.php └── template.yml
SAMテンプレートです
AWSTemplateFormatVersion: 2010-09-09 Description: My PHP Application Transform: AWS::Serverless-2016-10-31 Resources: phpserver: Type: AWS::Serverless::Function Properties: FunctionName: !Sub ${AWS::StackName}-phpserver Description: PHP Webserver CodeUri: src/php Runtime: provided Handler: index.php MemorySize: 3008 Timeout: 30 Tracing: Active Layers: - !Sub arn:aws:lambda:${AWS::Region}:887080169480:layer:php71:4 Events: api: Type: Api Properties: Path: /{proxy+} Method: ANY
Layersで指定しているarn:aws:lambda:${AWS::Region}:887080169480:layer:php71:4
がStackery社から提供されているCustom Runtimeのレイヤーになります。
PHPのソースコードです
<?php phpinfo();
デプロイ
まずはここまでで一旦デプロイしてみます。
sam package --template-file template.yml --output-template-file serverless-output.yaml --s3-bucket <S3バケット名>
sam deploy --template-file serverless-output.yaml --stack-name custom-runtime-php71 --capabilities CAPABILITY_IAM
テスト
作成されたAPI GW のエンドポイントにブラウザからアクセスしてみます。
動きました!!
Extensionの導入と有効化
次にExtensionの導入と有効化を行います。
READMEによると2018/12/2現在下記のExtensionについてはCustom Runtimeのレイヤー内に導入済みとのことです。
bz2.so calendar.so ctype.so curl.so dom.so exif.so fileinfo.so ftp.so gettext.so iconv.so json.so phar.so posix.so shmop.so simplexml.so sockets.so sysvmsg.so sysvsem.so sysvshm.so tokenizer.so wddx.so xml.so xmlreader.so xmlwriter.so xsl.so zip.so
上記のExtensionについてはデプロイパッケージ内のphp.ini
に
extension=json.so
のような記述を追加することで有効化することが可能です。
このブログでは、デフォルトでは導入されないExtensionを導入してみます!!
Extension追加の手順
PHPのExtension追加手順はざっくり下記の通りになります。
- Extensionをビルドする
- ビルドしたExtensionを含むレイヤーを追加
今回はPHPのExtensionの1つXdebugを追加してみます。
Xdebugのビルド
Extensionのビルドにはlambci/lambda:build-nodejs8.10のDockerイメージを使うのが推奨されている様です。 PHPのビルドなのになんでNode?!と思いますが依存関係のあるライブラリが良い感じに揃っていたのではないかと推測されます。
下記のDockerfileを使ってxdebugをビルドします。
FROM lambci/lambda:build-nodejs8.10 RUN yum install -y php71-devel \ && curl -fsSL 'https://xdebug.org/files/xdebug-2.6.1.tgz' -o xdebug-2.6.1.tar.gz \ && mkdir -p xdebug-2.6.1 \ && tar -xf xdebug-2.6.1.tar.gz -C xdebug-2.6.1 --strip-components=1 \ && cd xdebug-2.6.1 \ && phpize \ && ./configure --enable-xdebug \ && make \ && make install
docker build -t cm-iwata/lambda_php_with_xdebug .
ビルドできたらコンテナを起動し、xdebug.soを抽出します。
docker cp <コンテナ名>:/usr/lib64/php/7.1/modules/xdebug.so .
Xdebug用のレイヤーを作成
ビルドしたxdebug.soをZIPに固めてXdebug用のレイヤーを作成します。
PHPのExtensionを読み込ませるためには、レイヤーが解凍された際にxdebug.soが/opt/lib/php/7.1/modules/xdebug.so
に配置される必要があります。
空のディレクトリをいくつか作成し、下記の様なディレクトリ構成でZIPに固めます。
. └── lib └── php └── 7.1 └── modules └── xdebug.so
ZIPが作成できたらマネジメントコンソールの「レイヤーの作成」からレイヤーを追加します。
先ほど作成したZIPファイルをアップロードしてレイヤを作成します。
Lambdaにレイヤーを追加
レイヤーが作成できたら最初にデプロイしたLambdaのレイヤーにXDebugのレイヤーを追加します。
php.iniを追加
Xdebugを読み込ませるためにデプロイパッケージにphp.iniを追加します。 ディレクトリ構成はこのようになります。
└── lambda │ ├── src │ │ └── php │ │ ├── index.php │ │ └── php.ini │ └── template.yml
php.iniの中身は下記のようになります。
zend_extension='xdebug.so'
Xdebugなのでextension=...
ではなくzend_extension=...
という記述になります。
php.iniが追加できたら再度デプロイしておきます。
確認してみる
ここまで出来たら再度API GWにアクセスし、phpinfoの出力を確認します。
Xdebug関連の出力が追加されました!! 無事Extensionが読み込めていそうです。
リモートデバッグしてみる
仕上げとしてXdebugを使ってAWS上で稼働するLambdaをローカルのEclipseからリモートデバッグしてみます。 Lambdaからローカルマシンに対してXDebugのセッションを張ってもらう必要があるので、踏み台用のEC2を立ててSSHのトンネルを利用してリモートデバッグします。
踏み台構築
適当にEC2を構築し、セキュリティグループの設定でSSHと9000番ポート(Xdebug用)へのアクセスを許可します。 EC2が起動したら、SSHのトンネル用にsshdの設定を変更します。
GatewayPorts yes
設定ファイルを変更したらリロードしておきます。
systemctl reload sshd
php.iniを修正
LambdaがEC2に対してXdebugのセッションを張るようにphp.iniの設定を変更します。 ついでにリモートデバッグ周りの設定も追加します。 SSHトンネルのオーバーヘッド等を考慮し、念のためタイムアウトを長めに取っています。
zend_extension='xdebug.so' xdebug.remote_host = <踏み台EC2のGIP> xdebug.remote_autostart = true xdebug.remote_enable = true xdebug.remote_timeout = 5000
修正できたら再度デプロイしておきます。
SSHのトンネルを掘る
ローカルマシンからEC2にSSHのトンネルを掘ります
ssh -g -i <秘密鍵のパス> -R *:9000:127.0.0.1:9000 ec2-user@<踏み台EC2のGIP>
これでLambda<->EC2<->ローカルマシンという流れでXdebugの通信が可能になります。
確認してみる
リモートデバッグできるように適宜IDEを設定した後にAPI GWのエンドポイントにアクセスすると・・・
止まりました!! 環境変数の中身がバッチリ確認できています。
まとめ
Lambdaカスタムランタイム環境(PHP用)にExtensionを追加導入する手順をご紹介しました。 Xdebugはネタ気味ですが、OPcacheやAPCuを導入したいと言うニーズは非常に多いと思います。 Xdebugの導入と手順は同じなので、ぜひ参考にしてみて下さい!!